/*----------------------------------------------------------------------
 *
 * Confidential and Proprietary to Taggle Systems / Widentifi Pty. Ltd.
 *
 *     Copyright 2009, Widentifi Pty. Ltd.  All rights reserved.
 *
 * This precautionary copyright notice against inadvertent publication
 * is neither an acknowledgement of publication, nor a waiver of
 * confidentiality.
 *
 *---------------------------------------------------------------------
 *
 * Very simple module to drive the lpcb across chip boundries.
 *
 *---------------------------------------------------------------------
 * $Id: lpcb_tx.v 667 2010-07-01 00:12:17Z jayshurtz $
 * $URL: http://hatch.googlecode.com/svn/tags/taggle_release_3.0/examples/modules/dcom_lpcb/lpcb_tx.v $
 * $Author: jayshurtz $
 *---------------------------------------------------------------------*/

`include "lpcb_defines.vh"

module lpcb_tx

  (/*AUTOARG*/
  // Outputs
  lpcb_tx_strobe, lpcb_tx_frame, lpcb_tx_cad,
  // Inputs
  clk, reset, lpcb_frame_in, lpcb_cad_in
  );

  //----------------------------------------
  input                 clk;
  input                 reset;
  //----------------------------------------

  //----------------------------------------
  // lpcb interface
  output                lpcb_tx_strobe;
  output                lpcb_tx_frame;
  output[3:0]           lpcb_tx_cad;

  input                 lpcb_frame_in;
  input [3:0]           lpcb_cad_in;
  //----------------------------------------


  /*----------------------------------------------------------------*/

  /*-AUTOUNUSED-*/

  /*AUTOINPUT*/

  /*AUTOOUTPUT*/

  /*-AUTOREGINPUT-*/

  /*AUTOREG*/

  /*AUTOWIRE*/

  /*------------------------------------------------------------------
   *
   * local definitions and connections.
   *
   * */

  /*------------------------------------------------------------------
   *
   * pipeline the incomming data to make timing easier.
   *
   * */

  reg                   lpcb_frame_int;
  reg [3:0]             lpcb_cad_int;
  always @ (posedge clk) begin
    if (reset) begin
      lpcb_frame_int <= 1'd0;
      lpcb_cad_int   <= 4'd0;
    end else begin
      lpcb_frame_int <= lpcb_frame_in;
      lpcb_cad_int   <= lpcb_cad_in;
    end
  end

  /*------------------------------------------------------------------
   *
   * buffer the incoming transaction.
   *
   * tx rate is 1/4 rx rate.
   *
   * Maximum length transaction would be a write (17 cycles) or a read
   * followed by read result (9 + 9 cycles).
   *
   * Fifo needs to be 18 x 3/4 => 14 elements, make it 16 for
   * convenience.
   *
   * */

  reg [3:0]             cad [0:15];
  reg                   frame [0:15];
  reg [4:0]             count;
  reg [3:0]             write_pointer;
  always @ (posedge clk) begin
    if (reset) begin
      count         <= 5'd0;
      write_pointer <= 4'd0;
      cad[write_pointer]   <= 4'd0;
      frame[write_pointer] <= 1'd0;
    end else begin
      if (lpcb_frame_int) begin
        // we have an incomming command.
        case(lpcb_cad_int)
          `LPCB_WRITE_8B_CMD  : count <= 5'd10;  // 2 addr + 8 data
          `LPCB_WRITE_16B_CMD : count <= 5'd12; // 4 addr + 8 data
          `LPCB_WRITE_24B_CMD : count <= 5'd14; // 6 addr + 8 data
          `LPCB_WRITE_32B_CMD : count <= 5'd16; // 8 addr + 8 data
          `LPCB_READ_8B_CMD   : count <= 5'd2;  // 2 addr
          `LPCB_READ_16B_CMD  : count <= 5'd4;  // 4 addr
          `LPCB_READ_24B_CMD  : count <= 5'd6;  // 6 addr
          `LPCB_READ_32B_CMD  : count <= 5'd8;  // 8 addr
          `LPCB_READ_ACK_CMD  : count <= 5'd8;  // 8 data
          default             : count <= 5'd0;
        endcase // case(lpcb_cad_a_int)
      end else if (count > 5'd0) begin
        count <= count - 5'd1;
      end

      if ((count > 5'd0) || lpcb_frame_int) begin
        // we are processing a command.
        cad[write_pointer]   <= lpcb_cad_int;
        frame[write_pointer] <= lpcb_frame_int;
        write_pointer <= write_pointer + 4'd1;
      end else begin
        // we are waiting for a command.
        cad[write_pointer]   <= 4'd0;
        frame[write_pointer] <= 1'd0;
      end
    end
  end

  /*-----------------------------------------------------------------
   *
   * output stage for chip to chip interface.
   *
   * */

  reg       lpcb_tx_strobe;
  reg       lpcb_tx_frame;
  reg [3:0] lpcb_tx_cad;
  reg [2:0] tx_div;
  reg [3:0] read_pointer;
  always @ (posedge clk) begin
    if (reset) begin
      tx_div         <= 3'd0;
      read_pointer   <= 4'd0;
      lpcb_tx_strobe <= 1'd0;
      lpcb_tx_frame  <= 1'd0;
      lpcb_tx_cad    <= 4'd0;
    end else begin
      tx_div <= tx_div + 3'd1;
      if (tx_div == 3'd0) begin
        if (read_pointer != write_pointer) begin
          // work to do.
          lpcb_tx_strobe <= 1'd1;
          lpcb_tx_frame  <= frame[read_pointer];
          lpcb_tx_cad    <= cad[read_pointer];
          read_pointer   <= read_pointer + 4'd1;
        end else begin
          lpcb_tx_strobe <= 1'd0;
          lpcb_tx_frame  <= 1'd0;
          lpcb_tx_cad    <= 4'd0;
        end
      end else if (tx_div == 3'd4) begin
        lpcb_tx_strobe <= 1'd0;
      end
    end
  end

  /*----------------------------------------------------------------*/

endmodule // lpcb_tx


// Local Variables:
// verilog-library-directories:(".")
// verilog-library-extensions:(".v")
// End:
